import { Loading } from 'element-ui';
import axios from 'axios';
import { isFileStream } from '@/utils/is';
import errorHandle from './errorHandle';
import { AxiosCanceler } from './axiosCanceler';

const axiosCanceler = new AxiosCanceler();

const instance = axios.create({
  timeout: 60 * 1000,
  baseURL: '/api'
});

/**
 * request 成功回调
 * @param {*} config
 * @returns
 */
const requestSuccess = function(config) {
  return config;
};

/**
 * request 失败回调
 * @param {*} err
 * @returns
 */
const requestError = function(err) {
  return Promise.reject(err);
};

/**
 * response 成功回调
 * @param {*} response
 * @returns
 */
const responseSuccess = function(response) {
  // 请求完成后将该请求在 axiosCanceler 移除
  axiosCanceler.removePending(response.config);
  const res = response.data;
  if (!isFileStream(res) && res.code !== 200 && res.code !== 0) {
    errorHandle(res);
    return Promise.reject(res);
  }
  return Promise.resolve(response);
};

/**
 * response 失败回调
 * @param {*} err
 * @returns
 */
const responseError = function(err) {
  // 判断当前请求错误的原因是否是主动 Cancel
  if (axios.isCancel(err)) {
    return Promise.reject(err);
  }
  errorHandle(err?.response);
  return Promise.reject(err);
};

instance.interceptors.request.use(requestSuccess, requestError);
instance.interceptors.response.use(responseSuccess, responseError);

export function request(config = {}) {
  let loading = null;
  const { hasLoading = false, needCancel = true, transformResult = true } = config;
  // 是否需要展示全局Loading框
  if (hasLoading) {
    loading = Loading.service({
      fullscreen: true,
      text: '加载中...',
      background: 'rgba(0, 0, 0, .3)'
    });
  }
  // 是否需要将该请求记录到canceler
  if (needCancel) {
    axiosCanceler.addPending(config);
  }

  return instance(config)
    .then((res) => {
      // 是否对返回数据处理，即去掉 axios 包装的一层 data
      // 需要读取response数据中 headers 等数据时设置该字段为 false
      // 默认为 true
      if (transformResult) return res.data;
      return res;
    }).catch((err) => {
      return Promise.reject(err);
    }).finally(() => {
      hasLoading && loading.close();
    });
}

/**
 * post请求
 * @param {*}
 * @returns
 */
export function post({
  url,
  method = 'post',
  data = {},
  params = {},
  hasLoading = false,
  headers = {},
  needCancel = true,
  transformResult = true
}) {
  const config = {
    method,
    url,
    params,
    data,
    headers,
    hasLoading,
    needCancel,
    transformResult
  };
  return request(config);
}

/**
 * get请求
 * @param {*} param
 * @returns
 */
export function get({
  url,
  params = {},
  hasLoading = false,
  headers = {},
  needCancel = true,
  transformResult = true
}) {
  const config = {
    method: 'get',
    url,
    params,
    headers,
    hasLoading,
    needCancel,
    transformResult
  };
  return request(config);
}

/**
 * 上传文件
 * @param {*} param0
 * @returns
 */
export function uploadFile({
  url,
  method = 'post',
  data,
  hasLoading = true,
  needCancel = true,
  transformResult = true
}) {
  const config = {
    headers: {
      'Content-Type': 'multipart/form-data;charset=UTF-8'
    },
    timeout: 200 * 1000,
    method,
    url,
    data,
    hasLoading,
    needCancel,
    transformResult
  };

  return request(config);
}

/**
 * 下载文件
 * @param {*} param0
 * @returns
 */
export async function downloadFile({
  url,
  method = 'get',
  params = {},
  data = {},
  hasLoading = true,
  fileName = '',
  needCancel = true,
  transformResult = false
}) {
  const config = {
    method,
    responseType: 'blob',
    url,
    params,
    data,
    timeout: 200 * 1000,
    hasLoading,
    needCancel,
    transformResult
  };
  return request(config)
    .then((res) => {
      fileName = fileName || res.headers['content-disposition'].split(';')[1].split('=')[1].trim().replaceAll('"', '');
      const a = document.createElement('a');
      a.href = URL.createObjectURL(res.data);
      a.download = fileName;
      a.click();
    }).catch((e) => {
      return Promise.reject(e);
    });
}
